from datetime import datetime
from turbogears.database import PackageHub
from sqlobject import *
from turbogears import identity

import doc
import doc_xml

import blockarticle.widget_manager as widget_manager
WidgetManager = widget_manager.WidgetManager()
WidgetManager.LoadWidgets()

hub = PackageHub('blockarticle')
__connection__ = hub

# identity models.
class Visit(SQLObject):
    """
    A visit to your site
    """
    class sqlmeta:
        table = 'visit'

    visit_key = StringCol(length=40, alternateID=True,
                          alternateMethodName='by_visit_key')
    created = DateTimeCol(default=datetime.now)
    expiry = DateTimeCol()

    def lookup_visit(cls, visit_key):
        try:
            return cls.by_visit_key(visit_key)
        except SQLObjectNotFound:
            return None
    lookup_visit = classmethod(lookup_visit)


class VisitIdentity(SQLObject):
    """
    A Visit that is link to a User object
    """
    visit_key = StringCol(length=40, alternateID=True,
                          alternateMethodName='by_visit_key')
    user_id = IntCol()


class Group(SQLObject):
    """
    An ultra-simple group definition.
    """
    # names like "Group", "Order" and "User" are reserved words in SQL
    # so we set the name to something safe for SQL
    class sqlmeta:
        table = 'tg_group'

    group_name = UnicodeCol(length=16, alternateID=True,
                            alternateMethodName='by_group_name')
    display_name = UnicodeCol(length=255)
    created = DateTimeCol(default=datetime.now)

    # collection of all users belonging to this group
    users = RelatedJoin('User', intermediateTable='user_group',
                        joinColumn='group_id', otherColumn='user_id')

    # collection of all permissions for this group
    permissions = RelatedJoin('Permission', joinColumn='group_id',
                              intermediateTable='group_permission',
                              otherColumn='permission_id')


class User(SQLObject):
    """
    Reasonably basic User definition.
    Probably would want additional attributes.
    """
    # names like "Group", "Order" and "User" are reserved words in SQL
    # so we set the name to something safe for SQL
    class sqlmeta:
        table = 'tg_user'

    user_name = UnicodeCol(length=16, alternateID=True,
                           alternateMethodName='by_user_name')
    email_address = UnicodeCol(length=255, alternateID=True,
                               alternateMethodName='by_email_address')
    display_name = UnicodeCol(length=255)
    password = UnicodeCol(length=40)
    created = DateTimeCol(default=datetime.now)

    # groups this user belongs to
    groups = RelatedJoin('Group', intermediateTable='user_group',
                         joinColumn='user_id', otherColumn='group_id')

    def _get_permissions(self):
        perms = set()
        for g in self.groups:
            perms = perms | set(g.permissions)
        return perms

    def _set_password(self, cleartext_password):
        "Runs cleartext_password through the hash algorithm before saving."
        password_hash = identity.encrypt_password(cleartext_password)
        self._SO_set_password(password_hash)

    def set_password_raw(self, password):
        "Saves the password as-is to the database."
        self._SO_set_password(password)


class Permission(SQLObject):
    """
    A relationship that determines what each Group can do
    """
    permission_name = UnicodeCol(length=16, alternateID=True,
                                 alternateMethodName='by_permission_name')
    description = UnicodeCol(length=255)

    groups = RelatedJoin('Group',
                         intermediateTable='group_permission',
                         joinColumn='permission_id',
                         otherColumn='group_id')

class Article(SQLObject):       
    # Title of this Article
    Title = UnicodeCol()
    # Create date of this Article
    CreateDate = DateTimeCol()
    # Update date of this Article
    UpdateDate = DateTimeCol()
    # Edition of this Article
    Edition = DecimalCol(size=10, precision=0)
    # Doc object 
    Doc = PickleCol()
    # XML doc content
    XMLDoc = StringCol()
    
    def updateArticle(self):
        import datetime
        #self.XMLDoc = doc_xml.DocToXML(Doc)
        self.UpdateDate = datetime.datetime.now()
        self.Edition += 1
        self.Doc = self.Doc
    
    def deleteWidget(self, ID):
        """Delete a widget from this article's doc
        
        @param ID: ID of widget to delete 
        """
        self.Doc[ID].DeleteFromParent()
        self.updateArticle()
        
    def insertWidget(self, ID, Type, PushBack):
        """Insert a widget to doc
        
        @param ID: Target widget's ID
        @param Type: Type of widget to insert
        @param PushBack: Push back or insert front
        @return: New widget
        """
        TypeClass = WidgetManager.GetWidget(Type)
        
        Node = self.Doc[ID]
        if PushBack == '0':
            NewNode = Node.InsertSiblingBefore(TypeClass())
        else:
            NewNode = Node.InsertBefore(None, TypeClass())
        
        self.updateArticle()
        return NewNode
    
    def modifyWidget(self, ID, **Kwargs):
        """Modify a widget
        
        @param ID: Target widget's ID
        @param **Kwargs: Params to modify the widget  
        @return: Widget that modified
        """
        self.Doc[ID].Modify(**Kwargs)
        self.updateArticle()
        return self.Doc[ID]
    
    def moveWidget(self, From, To, PushBack):
        """"Move a widget
        
        @param From: ID of widget to move from
        @param To: ID of widget to move to
        @param PushBack: Push back or insert front  
        @return: Widget that moved 
        """        
        FromNode = self.Doc[From]
        ToNode = self.Doc[To] 
        
        if PushBack == '0':
            ToNode.MoveSiblingBefore(FromNode)
        else:
            ToNode.MoveBefore(None, FromNode)
        
        self.updateArticle()
        return FromNode
    
    def copyWidget(self, From, To, PushBack):
        """"Copy a widget
        
        @param From: ID of widget to copy from
        @param To: ID of widget to copy to
        @param PushBack: Push back or insert front  
        @return: New widget that copied
        """        
        FromNode = self.Doc[From]
        ToNode = self.Doc[To] 
        
        if PushBack == '0':
            NewWidget = ToNode.CopySiblingBefore(FromNode)
        else:
            NewWidget = ToNode.CopyBefore(None, FromNode)
        
        self.updateArticle()
        return NewWidget
    
    def modifyTitle(self, Title):
        """Modify article's title
        
        @param Title: New title of this article 
        """
        self.Title = Title
        self.updateArticle()
        
    def deleteArticle(self):
        """Delete this article"""
        self.delete(id=self.id)

def createArticle(Title):
    """Create a article
    
    @param Title: Title of this article 
    """
    import datetime
    
    BlockBase = WidgetManager.GetWidget('widget_base.BlockBase')
    
    NewDoc = doc.Doc()
    NewDoc.Create(BlockBase)
    
    Article(Title=Title, CreateDate=datetime.datetime.now(), UpdateDate=datetime.datetime.now(), Edition=0, Doc = NewDoc, XMLDoc='')